#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <list>

#include <sys/socket.h>

#include "InitAddr.hpp"
#include "Log.hpp"
#include "Mutex.hpp"

using namespace LogModule;
using namespace LockModule;

class UserInterface
{
public:
	virtual ~UserInterface() = default;
	virtual void SendTo(int sockfd, const std::string &message) = 0;
	virtual bool operator==(const Inetaddr &u) = 0;
	virtual std::string Id() = 0;
};

class User : public UserInterface
{
public:
	User(const Inetaddr &id) : _id(id)
	{
	}
	void SendTo(int sockfd, const std::string &message) override
	{
		LOG(LogLevel::DEBUG) << "sendto to " << _id.addr() << " info " << message;
		int n = ::sendto(sockfd, message.c_str(), sizeof(message), 0, _id.Netaddr(), _id.NetaddrLen());
	}
	bool operator==(const Inetaddr &u) override
	{
		return _id == u;
	}
	std::string Id() override
    {
        return _id.addr();
    }
	~User()
	{
	}

private:
	Inetaddr _id;
};

// 对用户消息进行路由转发
// Router 把所有用户先进行管理起来
// 观察者模式 observer
class UserMessage
{
public:
	UserMessage()
	{
	}
	void AddUser(Inetaddr &id)
	{
		LockGuard Lockguard(_mut);
		{
			// 如果用户存在
			for (auto &user : _inile_user)
			{
				if (*user == id)
				{
					LOG(LogLevel::INFO) << "用户已经存在" << id.addr();
					return;
				}
			}
			// 不存在则插入
			LOG(LogLevel::INFO) << "新增用户：" << id.addr();
			_inile_user.push_back(std::make_shared<User>(id));
			PrintUser();
		}
	}
	void DelUser(Inetaddr &id)
	{
		LockGuard Lockguard(_mut);
		
		auto pos = std::remove_if(_inile_user.begin(), _inile_user.end(), [&id](std::shared_ptr<UserInterface> &user)
					   { return *user == id; });
	    _inile_user.erase(pos,_inile_user.end());
		PrintUser();

	}
	void Router(int sockfd, std::string &message)
	{
		LockGuard Lockguard(_mut);
		{
			for (auto &user : _inile_user)
			{
				user->SendTo(sockfd, message);
			}
		}
	}
	void PrintUser()
    {
        for(auto user : _inile_user)
        {
            LOG(LogLevel::DEBUG) <<"在线用户-> "<<  user->Id();
        }
    }
	~UserMessage()
	{
	}

private:
	std::list<std::shared_ptr<UserInterface>> _inile_user;
	Mutex _mut;
};